package lru

import (
  "container/list"
)



/* lru算法元素变量 */
type lruElement struct {
  key         string                      //  lru 算法使用key 以后考虑使用接口， 适用各种结构题
  timestamp   uint64                      //  时间戳
  pageViews   int32                       //  浏览数 - redis服务使用
  lruElemP    *list.Element               //  指向lruElement 方便lru操作
}

/* 增加浏览数 */
func (l *lruElement) addPageViews() {
    l.pageViews++
}

/* 把e移动到lru队列头 */
func (lru *Lru) moveToLruFront( e *lruElement ) bool {
    if nil == e || nil == e.lruElemP {
        return false
    }
    lru.queue.MoveToFront(e.lruElemP)
    return true
}

/* lru 结构体 根据key查到 lruElement元素 */
func (lru *Lru) findLruElement(key string) (e *lruElement, flag bool) {
    flag = false
    e = nil

    if "" == key {
        return
    }

    /* 遍历lru 寻找 lruElement */
    for element := lru.queue.Front() ; element != nil; element = element.Next() {
      if data, ok := element.Value.(lruElement) ; ok {
          if data.key == key {
              flag = true
              e = &data
              return
          }
      }else {
          /* 这种情况应该不会出现 */
          return
      }
    }
    return
}


/* 把元素放入到 lru队列 头*/
func (lru *Lru) putLruFront(e *lruElement) (delElement interface{}, flag bool) {
    flag = false

    if nil == e {
        return
    }

    if lru.length >= lru.size {
        delElement = lru.removeBack()
    }

    // 把元素放入lru的同时，把lru返回的Element指针保存下来
    e.lruElemP, flag = lru.pushFront(e)

    return
}

/* lru 核心算法 */
/* 以后考虑把key string 修正为interface类型 */
func (lru *Lru) Process ()  {
//func (lru *Lru) Process (insertKey string ) ( delKey string, flag bool ) {
  for {
      inData := <- InChan
      insertKey := inData.Key
      var flag bool = false
      var delElem interface {}
      var outData LruOutChan = LruOutChan{ Flag : false }

      // 查找元素是否存在
      if elem, ok := lru.findLruElement(insertKey); ok {
      // 判断元素类型 ， 肯定是 *lruElement
        lru.moveToLruFront( elem )                // 属于insert_key 的元素节点 移动到队列头
        elem.addPageViews( )                      // 属于insert_key 的元素节点，pageviews + 1
      } else {
          /* 属于insert_key 放入到 lru 队列 中*/
          /* 创建一个lru元素 */
          var e = lruElement { key : insertKey, pageViews : 0}
          delElem, flag = lru.putLruFront( &e )
          if flag && nil != delElem {
              if  delLruElem, flag := delElem.(*lruElement); flag {
                  //delKey = delLruElem.key
                  outData.DelKey = delLruElem.key
              }
          }

     }

    inData.ChanOut <- outData
  }
  return
}
